#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>

#include <stdio.h>
#include <stdint.h>
#include <util/delay.h>

#include "uart.h"
#include "parser.h"
#include "light.h"
#include "rc5.h"
#include "taster.h"
#include "adc.h"
#include "tv.h"

#define F_CPU 16000000 
#ifndef F_CPU
#define F_CPU 16000000             /* Oszillator-Frequency */
#endif
 
#define UART_UBRR_CALC(BAUD_,FREQ_) ((FREQ_)/((BAUD_)*16L)-1)
 
#define UART_BAUD_RATE 9600
 
void read_temp();
void read_lux();
//uint16_t read_adc(uint8_t);
uint16_t get_lux(uint16_t);

int light_auto = 0;

void do_light_auto()
{
	if(light_auto != 1) {
		return;
	}
	uint16_t ad = read_adc(1);
	uint16_t lux = get_lux(ad);
	light *l = light_alloc(lux);
	uint8_t pin = (uint8_t) light_calc(l);
	light_free(l);
	l = NULL;

	pin = (0x01 << pin);
	PORTB = pin;
}

void handle_light(const char **attr)
{
	if(strcmp(attr[1], "on") == 0) {
		light_auto = 0;
		PORTB = 0x00;
		PORTB = (0x01 << 7);
	} else if(strcmp(attr[1], "off") == 0) {
		light_auto = 0;
		PORTB = 0x00;
		PORTB = (0x01);
	} else if(strcmp(attr[1], "auto") == 0) {
		light_auto = 1;
	}
}

void parsed(void *userdata, char *tag, char **attr)
{
	if(strcmp(tag, "list_temp") == 0) {
		read_temp();
	} else if(strcmp(tag, "list_lux") == 0) {
		read_lux();
	} else if(strcmp(tag, "light") == 0) {
		handle_light(attr);
	}
}

/*uint16_t read_adc(uint8_t mux)
{
	uint16_t val;			// the value
	
	// setting up the ADC with frequency 4
	ADCSRA = (1<<ADEN) | (1<<ADPS1) | (1<<ADPS0);
	ADMUX = mux;			// select the channel
	ADMUX |= (1<<REFS0) | (1<<REFS1);	// select the referencevoltage
	
	ADCSRA |= (1<<ADSC);	// dummy-read
	
	val = 0;
	for(int i = 0; i < 4; ++i) {
		while(ADCSRA & (1<<ADSC)) {	// here we go...
			// wait for finish
		}
		val += ADCW;
	}
	// calculate the average of 4 measures
	val /= 4;
	// deactivate the ADC
	ADCSRA &= ~(1<<ADEN);
	return val;
}
*/

unsigned int calc_temp(unsigned int tmp)
{
	// 8,9 C 	... 601,6
	// 9,2 C 	... 594,63
	// 14 C 	... 497,03
	// 15 C 	... 472
	// 21,3 C 	... 384
	// 26,5 C 	... 325,74
	// 27 C 	... 323,25
	// 33,8 C	... 268.48
	// 34 C		... 263,49
	// 34,5 C	... 263
	// 47 C		... 201,75
	unsigned int rtrn = 0;
	if(tmp > 602) {
		rtrn = (unsigned int) 8.9 / 601.6 * tmp;
	} else if(tmp > 595) {
		rtrn = (unsigned int) (9.2 - ((9.2 - 8.9) / (601.6 - 594.63)) * ((double)tmp - 594.63));
	} else if(tmp > 498) {
		rtrn = (unsigned int) (14.0 - ((14.0 - 9.2) / (594.63 - 497.03)) * ((double)tmp - 497.03));
	} else if(tmp > 472) {
		rtrn = (unsigned int) (15.0 - ((15.0 - 14.0) / (497.03 - 472.0)) * ((double)tmp - 472.0));
	} else if(tmp > 384) {
		rtrn = (unsigned int) (21.3 - ((21.3 - 15.0) / (472.0 - 384.0)) * ((double)tmp - 384.0));
	} else if(tmp > 326) {
		rtrn = (unsigned int) (26.5 - ((26.5 - 21.3)  / (384.0 - 325.74)) * ((double)tmp - 325.74));
	} else if(tmp > 324) {
		rtrn = (unsigned int) (26.0 - ((27.0 - 26.5) / (325.74 - 323.25)) * ((double)tmp - 323.25));
	} else if(tmp > 269) {
		rtrn = (unsigned int) (33.8 - ((33.8 - 27.0) / (323.25 - 268.48)) * ((double)tmp - 268.48));
	} else if(tmp > 264) {
		rtrn = (unsigned int) (34.0 - ((34.0 - 33.8) / (268.48 - 263.49)) * ((double)tmp - 263.49));
	} else if(tmp > 202) { 
		rtrn = (unsigned int)(47.0 - ((47.0 - 34.0) / (263.49 - 201.75)) * ((double)tmp - 201.71));
	} else { // tmp > 47 C
		rtrn = (unsigned int) 47.0 / 201.75 * tmp;
	}
	
	return rtrn;
} 

void read_temp()
{
	uint16_t temp;
	char str[20];
	temp = read_adc(0);
	sprintf(str, "temp value %d \n", calc_temp(temp));
	uart_puts(str);
}

double calc_bright_resistance(uint16_t val)
{
	// calc voltage
	double volt = (5.0/1024.0) * (double)val;
	double resist = (4.8 * volt) / (5.0 - volt);
	return resist;
}

uint16_t get_lux(uint16_t val)
{
	double resist = calc_bright_resistance(val);
	// Lux-table for office-brightness (500 Lux max.)
	// 0.0	 lux		~7000 kO
	// 1.5	 lux		~500  kO
	// 10  	 lux		~57   kO
	// 62.5  lux		~9    kO
	// 125 	 lux		~6    kO
	// 187.5 lux		~5.5  kO
	// 250	 lux		~4.5  kO
	// 312.5 lux		~4.0  kO
	// 375   lux		~3.5  kO
	// 437.5 lux		~3.2  kO
	// 500 	 lux		~3.0  kO
	// 1000	 lux		~1.0  kO
	uint16_t rtrn = 0;
	if(resist < 1.0) {
		rtrn = 1000;
	} else if(resist < 3.0) { // bigger than 500 lux
		rtrn = (uint16_t) 1000.0 - 
			((1000.0 / 500.0) / (3.0 - 1.0)) * (resist - 1.0);
	} else if(resist < 3.2) { 
		rtrn = (uint16_t) (500.0 - 
			((500.0 - 437.5) / (3.2 - 3.0)) * (resist - 3.0));
	} else if(resist < 3.5) {
		rtrn = (uint16_t) (437.5 - 
			((437.5 - 375) / (3.5 - 3.2)) * (resist - 3.2));
	} else if(resist < 4.0) {
		rtrn = (uint16_t) (375 - 
			((375 - 312.5) / (4.0 - 3.5)) * (resist - 3.5));
	} else if(resist < 4.5) {
		rtrn = (uint16_t) (312.5 - 
			((312.5 - 250.0) / (4.5 - 4.0)) * (resist - 4.0));
	} else if(resist < 5.5) {
		rtrn = (uint16_t) (250.0 - 
			((250.0 - 187.5) / (5.5 - 4.5)) * (resist - 4.5));
	} else if(resist < 6.0) {
		rtrn = (uint16_t) (187.5 - 
			((187.5 - 125.0) / (6.0 - 5.5)) * (resist - 5.5));
	} else if(resist < 9.0) {
		rtrn = (uint16_t) (125.0 - 
			((125.0 - 62.5) / (9.0 - 6.0)) * (resist - 6.0));
	} else if(resist < 57.0) {
		rtrn = (uint16_t) (62.5 - 
			((62.5 - 10.0) / (57.0 - 9.0)) * (resist - 9.0));
	} else if(resist < 500.0) {
		rtrn = (uint16_t) (10 - 
			((10.0 - 1.5) / (500.0 - 57.0)) * (resist - 57.0));
	}
	return rtrn;
}

void read_lux()
{
	char buff[20];
	uint16_t val = read_adc(1);
	sprintf(buff, "lux value %d \n", get_lux(val));
	uart_puts(buff);
}

int main(void)
{	
	init_rs232();
	uart_flush();
	init_taster();
	init_tv();
	uart_puts("test\n\r");

	DDRC = 0xff;
	DDRB = 0xff;
	DDRD = 0xff;
	DDRD &= ~(1 << PD7);
	PORTC = 0x00;
	PORTB = 0x00;

	TCCR0 = 1 << CS02; 		// divide by 256
	TIMSK = 1 << TOIE0;		// enable timer interrupt

	parser *p = parser_create();
	p->callback = &parsed;

	int taster = -1;
	sei();
	int once = 1;
	while(1) {				// here we go...
	/*
		uint16_t c = uart_getc();
		if(c != -1) {
			parse_add(p, c);
			parse(p);
		}
		do_light_auto();
		_delay_us(1.0);
	*/
		taster = get_taster();
		if(taster != -1) {
			rc5 tmp = read_rc5();
			/* 
			 * we are only adding something if we are actually
			 * receiving sth.
			 */
			if(tmp.flip < 100) {
				tv_add_signal(tmp, taster);
				uart_puts("signal added on taster: ");
				uart_putc(taster + '0');
				uart_puts("\n\r");
			}
		}
		if(tv_storage[0].flip < 100 && once) {
			uart_puts("before send\n\r");
			send_rc5(tv_storage[0]);
			uart_puts("after send\n\r");
		}
		_delay_us(1.0);
	}
	parser_delete(p);
	return 0; // never reached
}

